package antLogic;

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import javax.swing.*;
import javax.swing.text.StyledDocument;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.border.*;
import javax.swing.event.*;

import com.jgoodies.forms.factories.*;
import com.jgoodies.forms.layout.*;
import com.jgoodies.plaf.plastic.PlasticLookAndFeel;
import com.jgoodies.plaf.plastic.theme.DesertBluer;


public class AntManager extends JFrame {

    DefaultListModel antListModel;
    public static AntManager antMgr;
    StyledDocument output;
    Style style0;
    Style styleWarn;
    Style styleError;
    AntStatusPanel statusPanel;
    Ant antToView;
    Coordinate positionToView;
    private Boolean dumpToFile = false;
    private Integer numLines;
    private Integer numLinesIteration;

    public AntManager() {
        initComponents();
        //A few UI tweaks
        mgrSplitPane.setDividerLocation(200 + mgrSplitPane.getInsets().left);
        mainPane.setDividerLocation(350 + mainPane.getInsets().top);
        statusPanel = new AntStatusPanel(this);
        CellConstraints cc = new CellConstraints();
        controlPanel.add(statusPanel, cc.xywh(3, 3, 1, 1, CellConstraints.FILL, CellConstraints.CENTER));
        statusPanel.setVisible(false);

        antListModel = new DefaultListModel();
        antList.setModel(antListModel);
        antListModel.addElement("World");
        generator = new Random(48625873);
        ants = new HashMap<Integer, Ant>();
        String DATE_FORMAT = "HH:mm:ss:SS";
        dateFormat = new SimpleDateFormat(DATE_FORMAT);
        cal = Calendar.getInstance(TimeZone.getDefault());

        numLines = 0;
        numLinesIteration = 1;

        //Style Output
        output = outputTPane.getStyledDocument();
        style0 = output.addStyle("earl", null);
        styleWarn = output.addStyle("warning", null);
        styleError = output.addStyle("error", null);
        StyleConstants.setBold(style0, true);
        StyleConstants.setBold(styleWarn, true);
        StyleConstants.setBold(styleError, true);
        StyleConstants.setForeground(style0, Color.blue);
        StyleConstants.setForeground(styleWarn, Color.red);
        StyleConstants.setForeground(styleError, Color.white);
        StyleConstants.setBackground(styleError, Color.red);

        //Shutdown hook
        Runtime runtime = Runtime.getRuntime();
        runtime.addShutdownHook(new ShutdownThread());
    }

    protected int getAntThreadSleepTime()  {
        return (Integer)antThreadSleepTimeSpinner.getValue();
    }

    protected int getWorldThreadSleepTime()  {
        return (Integer)worldThreadSleepTimeSpinner.getValue();
    }

    private void antListValueChanged(ListSelectionEvent e) {
        try {
            if (antList.getSelectedValue().equals("World")) {
                statusPanel.setVisible(false);
                borderPanel.setVisible(true);
            } else {
                borderPanel.setVisible(false);
                antToView = ants.get(Integer.parseInt(antList.getSelectedValue().toString().replace("#", "")));
                positionToView = new Coordinate(0, 0);
                statusPanel.setVisible(true);
                updateStatus();
            }
        } catch (Exception e1) {

        }
    }

    public void updateStatus() {
        statusPanel.loadAntData(antToView, positionToView);
    }

    private void startButtonActionPerformed(ActionEvent e) {
        if (startButton.getText().equals("Start")) {
            widthSpinner.setEnabled(false);
            heightSpinner.setEnabled(false);
            antQtySpinner.setEnabled(false);
            numAntsProcessedSpinner.setEnabled(false);
            unitDistanceSpinner.setEnabled(false);
            antSpeedSpinner.setEnabled(false);
            if (startColony((Integer) widthSpinner.getValue(), (Integer) heightSpinner.getValue(), (Integer) antQtySpinner.getValue()))
            {
                log(this, "World and Ant Colony Started");
                log(this, "Number of ants in world: " + ants.size());
                startButton.setText("Stop");
            } else {
                logError(this, "Could not create ant colony");
                startButton.setText("Start");
                widthSpinner.setEnabled(true);
                heightSpinner.setEnabled(true);
                antQtySpinner.setEnabled(true);
                numAntsProcessedSpinner.setEnabled(true);
                unitDistanceSpinner.setEnabled(true);
                antSpeedSpinner.setEnabled(true);
            }
        } else if (startButton.getText().equals("Stop")) {
            stop();
            logWarn(this, "World and ant colony stopped");
            widthSpinner.setEnabled(true);
            heightSpinner.setEnabled(true);
            antQtySpinner.setEnabled(true);
            numAntsProcessedSpinner.setEnabled(true);
            unitDistanceSpinner.setEnabled(true);
            antSpeedSpinner.setEnabled(true);
            startButton.setText("Start");
        }
    }

    private void clearButtonActionPerformed(ActionEvent e) {
        try {
            output.remove(0, output.getLength());
            numLines = 0;
            linesTField.setText(numLines.toString());
        } catch (BadLocationException e1) {

        }
    }

    private void scrollCBoxActionPerformed(ActionEvent e) {
        // TODO add your code here
    }

    private void dumpCBoxActionPerformed(ActionEvent e) {
    	if(dumpCBox.isSelected())
            dumpToFile = true;
        else
            dumpToFile = false;
    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents
        // Generated using JFormDesigner non-commercial license
        mainPane = new JSplitPane();
        mgrSplitPane = new JSplitPane();
        antListScrollPane = new JScrollPane();
        antList = new JList();
        controlPanel = new JPanel();
        borderPanel = new JPanel();
        antSpeedTextA = new JTextArea();
        antSpeedSpinner = new JSpinner();
        unitDistanceTextA = new JTextArea();
        unitDistanceSpinner = new JSpinner();
        numAntsProcessedTextA = new JTextArea();
        numAntsProcessedSpinner = new JSpinner();
        worldSizeLabel = new JLabel();
        widthSpinner = new JSpinner();
        heightSpinner = new JSpinner();
        antQtyLabel = new JLabel();
        antQtySpinner = new JSpinner();
        antThreadSleepTimeLabel = new JLabel();
        antThreadSleepTimeSpinner = new JSpinner();
        worldThreadSleepTimeLabel = new JLabel();
        worldThreadSleepTimeSpinner = new JSpinner();
        startButton = new JButton();
        panel1 = new JPanel();
        outputAreaScrollPane = new JScrollPane();
        outputTPane = new JTextPane();
        outputToolBar = new JToolBar();
        clearButton = new JButton();
        scrollCBox = new JCheckBox();
        dumpCBox = new JCheckBox();
        tBarSpacer = new JPanel();
        linesLabel = new JLabel();
        linesTField = new JTextField();
        CellConstraints cc = new CellConstraints();

        //======== this ========
        setTitle("Ant Manager");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setIconImage(null);
        Container contentPane = getContentPane();
        contentPane.setLayout(new FormLayout(
        	ColumnSpec.decodeSpecs("max(default;500dlu):grow"),
        	new RowSpec[] {
        		FormFactory.DEFAULT_ROWSPEC,
        		FormFactory.LINE_GAP_ROWSPEC,
        		new RowSpec("max(min;300dlu):grow")
        	}));

        //======== mainPane ========
        {
        	mainPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
        	mainPane.setResizeWeight(0.4);

        	//======== mgrSplitPane ========
        	{
        		mgrSplitPane.setResizeWeight(0.2);

        		//======== antListScrollPane ========
        		{

        			//---- antList ----
        			antList.addListSelectionListener(new ListSelectionListener() {
        				public void valueChanged(ListSelectionEvent e) {
        					antListValueChanged(e);
        				}
        			});
        			antListScrollPane.setViewportView(antList);
        		}
        		mgrSplitPane.setLeftComponent(antListScrollPane);

        		//======== controlPanel ========
        		{
        			controlPanel.setLayout(new FormLayout(
        				new ColumnSpec[] {
        					new ColumnSpec(ColumnSpec.LEFT, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
        					FormFactory.UNRELATED_GAP_COLSPEC,
        					new ColumnSpec(ColumnSpec.LEFT, Sizes.dluX(233), FormSpec.DEFAULT_GROW),
        					FormFactory.UNRELATED_GAP_COLSPEC,
        					new ColumnSpec(ColumnSpec.LEFT, Sizes.DEFAULT, FormSpec.DEFAULT_GROW)
        				},
        				new RowSpec[] {
        					new RowSpec(RowSpec.CENTER, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
        					FormFactory.UNRELATED_GAP_ROWSPEC,
        					new RowSpec(RowSpec.FILL, Sizes.dluY(229), FormSpec.DEFAULT_GROW),
        					FormFactory.UNRELATED_GAP_ROWSPEC,
        					new RowSpec(RowSpec.CENTER, Sizes.DEFAULT, FormSpec.DEFAULT_GROW)
        				}));

        			//======== borderPanel ========
        			{
        				borderPanel.setBorder(new TitledBorder("Settings"));
        				borderPanel.setLayout(new FormLayout(
        					new ColumnSpec[] {
        						FormFactory.DEFAULT_COLSPEC,
        						FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
        						new ColumnSpec(ColumnSpec.FILL, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
        						FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
        						new ColumnSpec(ColumnSpec.FILL, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
        						FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
        						new ColumnSpec(ColumnSpec.FILL, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
        						FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
        						new ColumnSpec(ColumnSpec.FILL, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
        						FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
        						FormFactory.DEFAULT_COLSPEC
        					},
        					new RowSpec[] {
        						FormFactory.DEFAULT_ROWSPEC,
        						FormFactory.LINE_GAP_ROWSPEC,
        						FormFactory.DEFAULT_ROWSPEC,
        						FormFactory.LINE_GAP_ROWSPEC,
        						FormFactory.DEFAULT_ROWSPEC,
        						FormFactory.LINE_GAP_ROWSPEC,
        						new RowSpec(Sizes.DLUY5),
        						FormFactory.LINE_GAP_ROWSPEC,
        						FormFactory.DEFAULT_ROWSPEC,
        						FormFactory.LINE_GAP_ROWSPEC,
        						FormFactory.DEFAULT_ROWSPEC,
        						FormFactory.LINE_GAP_ROWSPEC,
        						FormFactory.DEFAULT_ROWSPEC,
        						FormFactory.LINE_GAP_ROWSPEC,
        						FormFactory.DEFAULT_ROWSPEC,
        						FormFactory.LINE_GAP_ROWSPEC,
        						new RowSpec("max(default;31dlu)")
        					}));

        				//---- antSpeedTextA ----
        				antSpeedTextA.setText("Ant Speed (steps per second)");
        				antSpeedTextA.setLineWrap(true);
        				antSpeedTextA.setEditable(false);
        				antSpeedTextA.setFont(new Font("Segoe UI", Font.PLAIN, 11));
        				antSpeedTextA.setWrapStyleWord(true);
        				antSpeedTextA.setOpaque(false);
        				borderPanel.add(antSpeedTextA, cc.xywh(3, 1, 3, 1));

        				//---- antSpeedSpinner ----
        				antSpeedSpinner.setModel(new SpinnerNumberModel(5, 1, null, 1));
        				borderPanel.add(antSpeedSpinner, cc.xywh(7, 1, 3, 1, CellConstraints.FILL, CellConstraints.DEFAULT));

        				//---- unitDistanceTextA ----
        				unitDistanceTextA.setLineWrap(true);
        				unitDistanceTextA.setText("Unit distance size (in ant steps)");
        				unitDistanceTextA.setEditable(false);
        				unitDistanceTextA.setFont(new Font("Segoe UI", Font.PLAIN, 11));
        				unitDistanceTextA.setWrapStyleWord(true);
        				unitDistanceTextA.setOpaque(false);
        				borderPanel.add(unitDistanceTextA, cc.xywh(3, 3, 3, 1));

        				//---- unitDistanceSpinner ----
        				unitDistanceSpinner.setModel(new SpinnerNumberModel(5, 0, null, 1));
        				borderPanel.add(unitDistanceSpinner, cc.xywh(7, 3, 3, 1, CellConstraints.FILL, CellConstraints.DEFAULT));

        				//---- numAntsProcessedTextA ----
        				numAntsProcessedTextA.setText("Number of ants processed in one world loop");
        				numAntsProcessedTextA.setEditable(false);
        				numAntsProcessedTextA.setLineWrap(true);
        				numAntsProcessedTextA.setWrapStyleWord(true);
        				numAntsProcessedTextA.setFont(new Font("Segoe UI", Font.PLAIN, 11));
        				numAntsProcessedTextA.setOpaque(false);
        				borderPanel.add(numAntsProcessedTextA, cc.xywh(3, 5, 3, 1));

        				//---- numAntsProcessedSpinner ----
        				numAntsProcessedSpinner.setModel(new SpinnerNumberModel(5, 1, null, 1));
        				borderPanel.add(numAntsProcessedSpinner, cc.xywh(7, 5, 3, 1));

        				//---- worldSizeLabel ----
        				worldSizeLabel.setText("World size (width x height)");
        				borderPanel.add(worldSizeLabel, cc.xywh(3, 9, 3, 1, CellConstraints.FILL, CellConstraints.FILL));

        				//---- widthSpinner ----
        				widthSpinner.setModel(new SpinnerNumberModel(50, 5, null, 1));
        				borderPanel.add(widthSpinner, cc.xywh(7, 9, 1, 1, CellConstraints.FILL, CellConstraints.DEFAULT));

        				//---- heightSpinner ----
        				heightSpinner.setModel(new SpinnerNumberModel(50, 5, null, 1));
        				borderPanel.add(heightSpinner, cc.xywh(9, 9, 1, 1, CellConstraints.FILL, CellConstraints.DEFAULT));

        				//---- antQtyLabel ----
        				antQtyLabel.setText("Number of Ants");
        				borderPanel.add(antQtyLabel, cc.xywh(3, 11, 3, 1, CellConstraints.FILL, CellConstraints.FILL));

        				//---- antQtySpinner ----
        				antQtySpinner.setModel(new SpinnerNumberModel(12, 0, null, 1));
        				borderPanel.add(antQtySpinner, cc.xywh(7, 11, 3, 1, CellConstraints.FILL, CellConstraints.FILL));

        				//---- antThreadSleepTimeLabel ----
        				antThreadSleepTimeLabel.setText("Ant Thread Sleep Time (ms)");
        				borderPanel.add(antThreadSleepTimeLabel, cc.xywh(3, 13, 3, 1, CellConstraints.FILL, CellConstraints.FILL));

        				//---- antThreadSleepTimeSpinner ----
        				antThreadSleepTimeSpinner.setModel(new SpinnerNumberModel(200, 30, null, 10));
        				borderPanel.add(antThreadSleepTimeSpinner, cc.xywh(7, 13, 3, 1));

        				//---- worldThreadSleepTimeLabel ----
        				worldThreadSleepTimeLabel.setText("World Thread Sleep Time (ms)");
        				borderPanel.add(worldThreadSleepTimeLabel, cc.xywh(3, 15, 3, 1, CellConstraints.FILL, CellConstraints.FILL));

        				//---- worldThreadSleepTimeSpinner ----
        				worldThreadSleepTimeSpinner.setModel(new SpinnerNumberModel(200, 30, null, 10));
        				borderPanel.add(worldThreadSleepTimeSpinner, cc.xywh(7, 15, 3, 1));

        				//---- startButton ----
        				startButton.setText("Start");
        				startButton.addActionListener(new ActionListener() {
        					public void actionPerformed(ActionEvent e) {
        						startButtonActionPerformed(e);
        					}
        				});
        				borderPanel.add(startButton, cc.xywh(3, 17, 7, 1, CellConstraints.FILL, CellConstraints.FILL));
        			}
        			controlPanel.add(borderPanel, cc.xywh(3, 3, 1, 1, CellConstraints.FILL, CellConstraints.CENTER));
        		}
        		mgrSplitPane.setRightComponent(controlPanel);
        	}
        	mainPane.setTopComponent(mgrSplitPane);

        	//======== panel1 ========
        	{
        		panel1.setLayout(new FormLayout(
        			ColumnSpec.decodeSpecs("default:grow"),
        			new RowSpec[] {
        				new RowSpec(RowSpec.CENTER, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
        				FormFactory.LINE_GAP_ROWSPEC,
        				FormFactory.DEFAULT_ROWSPEC
        			}));

        		//======== outputAreaScrollPane ========
        		{

        			//---- outputTPane ----
        			outputTPane.setEditable(false);
        			outputAreaScrollPane.setViewportView(outputTPane);
        		}
        		panel1.add(outputAreaScrollPane, cc.xywh(1, 1, 1, 1, CellConstraints.FILL, CellConstraints.FILL));

        		//======== outputToolBar ========
        		{
        			outputToolBar.setFloatable(false);
        			outputToolBar.setRollover(true);

        			//---- clearButton ----
        			clearButton.setText("Clear Output");
        			clearButton.setToolTipText("Cleared output will not appear in dump file");
        			clearButton.setIcon(UIManager.getIcon("InternalFrame.paletteCloseIcon"));
        			clearButton.addActionListener(new ActionListener() {
        				public void actionPerformed(ActionEvent e) {
        					clearButtonActionPerformed(e);
        				}
        			});
        			outputToolBar.add(clearButton);

        			//---- scrollCBox ----
        			scrollCBox.setText("Scroll To Bottom on Output");
        			scrollCBox.addActionListener(new ActionListener() {
        				public void actionPerformed(ActionEvent e) {
        					scrollCBoxActionPerformed(e);
        				}
        			});
        			outputToolBar.add(scrollCBox);

        			//---- dumpCBox ----
        			dumpCBox.setText("Dump to file on clear & exit");
        			dumpCBox.addActionListener(new ActionListener() {
        				public void actionPerformed(ActionEvent e) {
        					dumpCBoxActionPerformed(e);
        				}
        			});
        			outputToolBar.add(dumpCBox);

        			//======== tBarSpacer ========
        			{
        				tBarSpacer.setLayout(new FormLayout(
        					"default:grow",
        					"default"));
        			}
        			outputToolBar.add(tBarSpacer);

        			//---- linesLabel ----
        			linesLabel.setText("Lines: ");
        			outputToolBar.add(linesLabel);

        			//---- linesTField ----
        			linesTField.setEditable(false);
        			linesTField.setOpaque(false);
        			linesTField.setColumns(6);
        			linesTField.setPreferredSize(new Dimension(15, 22));
        			linesTField.setBorder(null);
        			linesTField.setMaximumSize(new Dimension(60, 2147483647));
        			outputToolBar.add(linesTField);
        		}
        		panel1.add(outputToolBar, cc.xy(1, 3));
        	}
        	mainPane.setBottomComponent(panel1);
        }
        contentPane.add(mainPane, cc.xywh(1, 3, 1, 1, CellConstraints.DEFAULT, CellConstraints.FILL));
        setSize(770, 735);
        setLocationRelativeTo(getOwner());
        // JFormDesigner - End of component initialization  //GEN-END:initComponents
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables
    // Generated using JFormDesigner non-commercial license
    private JSplitPane mainPane;
    private JSplitPane mgrSplitPane;
    private JScrollPane antListScrollPane;
    private JList antList;
    private JPanel controlPanel;
    private JPanel borderPanel;
    private JTextArea antSpeedTextA;
    private JSpinner antSpeedSpinner;
    private JTextArea unitDistanceTextA;
    private JSpinner unitDistanceSpinner;
    private JTextArea numAntsProcessedTextA;
    private JSpinner numAntsProcessedSpinner;
    private JLabel worldSizeLabel;
    private JSpinner widthSpinner;
    private JSpinner heightSpinner;
    private JLabel antQtyLabel;
    private JSpinner antQtySpinner;
    private JLabel antThreadSleepTimeLabel;
    private JSpinner antThreadSleepTimeSpinner;
    private JLabel worldThreadSleepTimeLabel;
    private JSpinner worldThreadSleepTimeSpinner;
    private JButton startButton;
    private JPanel panel1;
    private JScrollPane outputAreaScrollPane;
    private JTextPane outputTPane;
    private JToolBar outputToolBar;
    private JButton clearButton;
    private JCheckBox scrollCBox;
    private JCheckBox dumpCBox;
    private JPanel tBarSpacer;
    private JLabel linesLabel;
    private JTextField linesTField;
    // JFormDesigner - End of variables declaration  //GEN-END:variables

    // -----------------------------------
    // -- Non GUI related
    // -----------------------------------

    protected HashMap<Integer, Ant> ants;
    protected static World world;
    protected Integer numStepsPerUnit;

    private Random generator;
    private Calendar cal;
    private SimpleDateFormat dateFormat;
    protected Boolean worldStarted = false;
    protected Integer numAntsReady;

    protected void log(Object sender, String logEntry) {
        try {
            String text = dateFormat.format(new Date()) + " : " + sender.getClass().getName() + " : ";
            output.insertString(output.getLength(), text, null);
            output.insertString(output.getLength(), logEntry + "\n", style0);
            numLines++;
            linesTField.setText(numLines.toString());
        } catch (Exception e) {
            System.err.println("Couldn't log to output: " + e.getMessage());
        }
        if(scrollCBox.isSelected())  {
            scrollToBottom();
        }

        if(numLines > (25000 * numLinesIteration)) {
            try {
                File dumpFile = null;
                if (dumpToFile) {
                    dumpFile = new File("/tmp/AntLogic." + (new Date()).getTime() + "");
                    FileWriter fileWriter = new FileWriter(dumpFile);
                    fileWriter.append("----------- Beginning of " + numLines + " lines.");
                    fileWriter.append(output.getText(0, output.getLength()));
                    fileWriter.append("----------- End of " + numLines + " lines.");
                    fileWriter.flush();
                    fileWriter.close();
                }
                output.remove(0, output.getLength());
                    numLinesIteration++;
                    linesTField.setText(numLines.toString());
                logWarn(this, "Output area exceeding 25 000 lines. Cleared");
                if (dumpToFile) {
                    logWarn(this, "Saved previous output to " + dumpFile.getAbsoluteFile().getName());
                }
            } catch (Exception e) {
                try {
                    output.remove(0, output.getLength());
                    numLinesIteration++;
                    linesTField.setText(numLines.toString());
                } catch (BadLocationException e1) {

                }
            }
        }
    }

    protected void logWarn(Object sender, String logEntry) {
        try {
            String text = dateFormat.format(new Date()) + " : " + sender.getClass().getName() + " : ";
            output.insertString(output.getLength(), text + logEntry + "\n", styleWarn);
            numLines++;
            linesTField.setText(numLines.toString());
        } catch (BadLocationException e) {
            System.err.println("Couldn't log to warning output: " + e.getMessage());
        }
    }

    protected void logError(Object sender, String logEntry) {
        try {
            String text = dateFormat.format(new Date()) + " : " + sender.getClass().getName() + " : ";
            output.insertString(output.getLength(), text, null);
            output.insertString(output.getLength(), logEntry + "\n", styleError);
            numLines++;
            linesTField.setText(numLines.toString());
        } catch (BadLocationException e) {
            System.err.println("Couldn't log to error output: " + e.getMessage());
        }
    }

    protected int getNumLiveAnts() {
        return ants.size();
    }

    protected void scrollToBottom() {
        Rectangle visible = outputTPane.getVisibleRect();
        visible.y = outputTPane.getHeight() - visible.height;
        outputTPane.scrollRectToVisible(visible);
    }

    protected synchronized void handleEvent(Event newEvent, int antId) {
        AntManager.antMgr.log(this, "Received event " + newEvent.getEventType() + " for ant #" + antId);
        if (ants.containsKey(antId)) {
            ants.get(antId).queueEvent(newEvent);
        } else {
            AntManager.antMgr.log(this, "Ant #" + antId + " does not exist");
        }
    }

    private boolean startColony(int width, int height, int numAnts) {
        numStepsPerUnit = (Integer) unitDistanceSpinner.getValue();
        numAntsReady = 0;
        world = new World(width, height, new Coordinate(width / 2, height / 2), (Integer) unitDistanceSpinner.getValue(), (Integer) numAntsProcessedSpinner.getValue(),getWorldThreadSleepTime());
        world.start();
        //Wait for world to be complete
        while (!worldStarted) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {

            }
        }
        Ant newAnt;
        for (int i = 0; i < numAnts; i++) {
            newAnt = world.addAnt(new Counter(360, generator.nextInt(360)), new Coordinate(generator.nextInt(world.width), generator.nextInt(world.height)), (Integer) antSpeedSpinner.getValue());
            ants.put(newAnt.getAntId(), newAnt);
            antListModel.addElement("#" + newAnt.getAntId());
        }
        while (numAntsReady != ants.size()) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {

            }
        }
        for (Ant ant : ants.values()) {
            ant.start();
        }
        return true;
    }


    private  void stop() {
        synchronized(ants) {
            for (Ant ant : ants.values()) {

            ant.interrupt();
        }
        world.interrupt();
        antListModel.removeAllElements();
        antListModel.addElement("World");
        worldStarted = false;
        numAntsReady = 0;
        }
    }

    protected void rmAnt(int antId) {
        try {
            Coordinate antLocation = world.antLocations.get(antId);
            world.map.rmItem(antId, antLocation);
            world.antLocations.remove(antId);
            ants.remove(antId);
            logWarn(this, "Removed ant #" + antId);
        } catch (Exception e) {
            logWarn(this, "Could not remove ant #" + antId);
        }
    }

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel("com.jgoodies.plaf.plastic.Plastic3DLookAndFeel");
            PlasticLookAndFeel.setMyCurrentTheme(new DesertBluer());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (UnsupportedLookAndFeelException e) {
            e.printStackTrace();
        }
        antMgr = new AntManager();
        antMgr.pack();
        antMgr.setVisible(true);
    }

    class ShutdownThread extends Thread {
        File dumpFile;

        ShutdownThread() {
            dumpFile = new File("/tmp/AntLogic." + (new Date()).getTime() + "");
        }

        public void run() {
            try {
                if (dumpToFile) {
                    System.out.println("Dumping output to file " + dumpFile.getName());
                    FileWriter fileWriter = new FileWriter(dumpFile);
                    fileWriter.append("----------- Beginning of " + numLines + " lines.");
                    fileWriter.append(output.getText(0, output.getLength()));
                    fileWriter.append("----------- End of " + numLines + " lines.");
                    fileWriter.flush();
                    fileWriter.close();
                }
            } catch (Exception e) {
                System.err.println("Could not dump output: " + e.getMessage());
                e.printStackTrace();
            }
        }
    }
}
